package org.rency.mq.activemq.listener.handler.impl;

import com.alibaba.fastjson.JSON;
import org.rency.mq.activemq.constant.DeliveryMode;
import org.rency.mq.activemq.constant.DestinationType;
import org.rency.mq.activemq.constant.MessageFormat;
import org.rency.mq.activemq.exception.MQException;
import org.rency.mq.activemq.jms.service.JmsAccessor;
import org.rency.mq.activemq.request.MQRequest;
import org.rency.mq.activemq.utils.JsonMessageUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jms.JMSException;
import javax.jms.Session;
import java.util.LinkedHashMap;
import java.util.Map;

public class RetryMessageHandler extends AbstractHandler {

    private static Logger logger = LoggerFactory.getLogger(RetryMessageHandler.class);
    private JmsAccessor mqAccessor;

    public void setMqAccessor(JmsAccessor mqAccessor) {
		this.mqAccessor = mqAccessor;
	}

	public void handleMessage(Object request) throws Exception {
		logger.info("Retry message: {}",request);
		
		if (request instanceof MQRequest) {
			MQRequest mqRequest = (MQRequest) request;
            try {
            	mqAccessor.sendMessage(mqRequest);
            } catch (MQException e) {
				logger.error("Retry to resend message failed.",e);

                if (mqRequest.getProperties() != null) {
                    String failedQueue = (String) mqRequest.getProperties().get("failedQueue");

                    if (failedQueue != null) {
                    	mqAccessor.sendMessage(failedQueue, DestinationType.QUEUE, MessageFormat.JSON, false,
        				        1, DeliveryMode.PERSISTENT, JSON.toJSONString(request));
                    }
                }
            }
		} else if (request instanceof String) {
			try{
				retry((String) request);
			}catch(Exception e){
				logger.error("Retry to resend message failed.",e);
				
				Map map = JSON.parseObject((String) request, LinkedHashMap.class);
				
				map = (Map) map.get("properties");
				
				if(map != null && !map.isEmpty()){
					String failedQueue = (String)map.get("failedQueue");
					
					if(failedQueue != null){
						try {
							mqAccessor.sendMessage(failedQueue,
									DestinationType.QUEUE, MessageFormat.JSON, false,
									Session.AUTO_ACKNOWLEDGE,
									DeliveryMode.PERSISTENT, (String)request);
						} catch (Exception e1) {
							logger.error("Send message to failedQueue failed.",e1);
						}
					}
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	private void retry(String request) throws Exception {
		try {
			Map map = JSON.parseObject((String) request, LinkedHashMap.class);

			boolean transcated = false;
			String destination = null;
			int destinationType = 0;
			int deliveryMode = JsonMessageUtils.getDeliveryMode(map);
			int acknowledgeMode = JsonMessageUtils.getAcknowledgeMode(map);

			if (map.containsKey("destination")) {
				transcated = (Boolean) map.get("transacted");
				destination = (String) map.get("destination");
				destinationType = (Integer) map.get("destinationType");
			} else {
				destination = (String) map.get("Destination");
				destinationType = (Integer) map.get("DestinationType");

				if (acknowledgeMode == Session.SESSION_TRANSACTED) {
					transcated = true;
				}
			}

			mqAccessor.sendMessage(destination, destinationType, MessageFormat.JSON, transcated,
					acknowledgeMode, deliveryMode, request);
		} catch (JMSException e) {
			logger.error("send message to retry queue failed. Request: {}.",request, e);
			throw e;
		} catch (Exception e) {
			logger.warn("Unmarshalling mqrequest failed.", e);
		}
	}
}
